# feoa.gfelz.com 企业微信登录快速部署脚本
# 适用于生产环境部署

param(
    [string]$Action = "deploy",  # deploy, test, rollback
    [string]$Environment = "production",
    [switch]$SkipBuild = $false,
    [switch]$SkipTest = $false,
    [switch]$Force = $false
)

# 配置变量
$Config = @{
    # 域名配置
    Domain = "feoa.gfelz.com"
    ApiPort = 6729
    H5Port = 6730
    
    # 路径配置
    ServicePath = "Service"
    H5Path = "RefundAuditAndroid"
    BackupPath = "backup"
    LogPath = "logs"
    
    # SSL证书配置
    SSLCertPath = "Service/ssl/lzetyy.com.pem"
    SSLKeyPath = "Service/ssl/lzetyy.com.key"
    
    # 部署配置
    ServiceName = "Lzfy_His_Service"
    ProcessName = "Lzfy_His_Service"
    
    # 企业微信配置验证
    RequiredEnvVars = @(
        "WECHAT_CORP_ID",
        "WECHAT_CORP_SECRET", 
        "WECHAT_AGENT_ID",
        "WECHAT_TOKEN",
        "WECHAT_ENCODING_AES_KEY"
    )
}

# 日志函数
function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "[$timestamp] [$Level] $Message"
    Write-Host $logMessage
    
    # 写入日志文件
    $logFile = "$($Config.LogPath)/deploy-$(Get-Date -Format 'yyyyMMdd').log"
    if (!(Test-Path (Split-Path $logFile))) {
        New-Item -ItemType Directory -Path (Split-Path $logFile) -Force | Out-Null
    }
    Add-Content -Path $logFile -Value $logMessage
}

# 错误处理
function Handle-Error {
    param([string]$Message, [Exception]$Exception = $null)
    Write-Log "错误: $Message" "ERROR"
    if ($Exception) {
        Write-Log "异常详情: $($Exception.Message)" "ERROR"
    }
    exit 1
}

# 检查先决条件
function Test-Prerequisites {
    Write-Log "检查部署先决条件..."
    
    # 检查.NET运行时
    try {
        $dotnetVersion = dotnet --version
        Write-Log "检测到.NET版本: $dotnetVersion"
    } catch {
        Handle-Error "未找到.NET运行时，请先安装.NET 9.0" $_
    }
    
    # 检查Node.js (用于前端构建)
    try {
        $nodeVersion = node --version
        Write-Log "检测到Node.js版本: $nodeVersion"
    } catch {
        Handle-Error "未找到Node.js，请先安装Node.js" $_
    }
    
    # 检查SSL证书
    if (!(Test-Path $Config.SSLCertPath)) {
        Handle-Error "SSL证书文件不存在: $($Config.SSLCertPath)"
    }
    if (!(Test-Path $Config.SSLKeyPath)) {
        Handle-Error "SSL密钥文件不存在: $($Config.SSLKeyPath)"
    }
    Write-Log "SSL证书文件检查通过"
    
    # 检查端口占用
    $apiPortInUse = Get-NetTCPConnection -LocalPort $Config.ApiPort -ErrorAction SilentlyContinue
    $h5PortInUse = Get-NetTCPConnection -LocalPort $Config.H5Port -ErrorAction SilentlyContinue
    
    if ($apiPortInUse -and !$Force) {
        Handle-Error "端口 $($Config.ApiPort) 已被占用，请使用 -Force 参数强制部署"
    }
    if ($h5PortInUse -and !$Force) {
        Handle-Error "端口 $($Config.H5Port) 已被占用，请使用 -Force 参数强制部署"
    }
    
    Write-Log "先决条件检查完成"
}

# 验证企业微信配置
function Test-WeChatConfig {
    Write-Log "验证企业微信配置..."
    
    $missingVars = @()
    foreach ($var in $Config.RequiredEnvVars) {
        if (!(Get-ChildItem Env: | Where-Object Name -eq $var)) {
            $missingVars += $var
        }
    }
    
    if ($missingVars.Count -gt 0) {
        Write-Log "警告: 以下环境变量未设置: $($missingVars -join ', ')" "WARN"
        Write-Log "请确保在appsettings.json中配置了相应的企业微信参数" "WARN"
    } else {
        Write-Log "企业微信环境变量配置完整"
    }
}

# 创建备份
function New-Backup {
    Write-Log "创建部署备份..."
    
    $backupDir = "$($Config.BackupPath)/backup-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
    New-Item -ItemType Directory -Path $backupDir -Force | Out-Null
    
    # 备份服务端
    if (Test-Path "$($Config.ServicePath)/publish") {
        Copy-Item "$($Config.ServicePath)/publish" "$backupDir/service" -Recurse -Force
        Write-Log "服务端备份完成"
    }
    
    # 备份前端
    if (Test-Path "$($Config.H5Path)/dist") {
        Copy-Item "$($Config.H5Path)/dist" "$backupDir/h5" -Recurse -Force
        Write-Log "前端备份完成"
    }
    
    # 备份配置文件
    if (Test-Path "$($Config.ServicePath)/appsettings.json") {
        Copy-Item "$($Config.ServicePath)/appsettings.json" "$backupDir/" -Force
        Write-Log "配置文件备份完成"
    }
    
    Write-Log "备份创建完成: $backupDir"
    return $backupDir
}

# 停止现有服务
function Stop-Services {
    Write-Log "停止现有服务..."
    
    # 停止Windows服务
    $service = Get-Service -Name $Config.ServiceName -ErrorAction SilentlyContinue
    if ($service -and $service.Status -eq "Running") {
        Stop-Service -Name $Config.ServiceName -Force
        Write-Log "Windows服务已停止"
    }
    
    # 停止进程
    $processes = Get-Process -Name $Config.ProcessName -ErrorAction SilentlyContinue
    if ($processes) {
        $processes | Stop-Process -Force
        Write-Log "相关进程已停止"
    }
    
    # 等待端口释放
    $timeout = 30
    $elapsed = 0
    while ($elapsed -lt $timeout) {
        $portInUse = Get-NetTCPConnection -LocalPort $Config.ApiPort -ErrorAction SilentlyContinue
        if (!$portInUse) {
            break
        }
        Start-Sleep -Seconds 1
        $elapsed++
    }
    
    if ($elapsed -ge $timeout) {
        Write-Log "警告: 端口释放超时" "WARN"
    }
    
    Write-Log "服务停止完成"
}

# 构建服务端
function Build-Service {
    if ($SkipBuild) {
        Write-Log "跳过服务端构建"
        return
    }
    
    Write-Log "构建服务端应用..."
    
    Push-Location $Config.ServicePath
    try {
        # 清理之前的构建
        if (Test-Path "publish") {
            Remove-Item "publish" -Recurse -Force
        }
        
        # 还原NuGet包
        Write-Log "还原NuGet包..."
        dotnet restore
        if ($LASTEXITCODE -ne 0) {
            throw "NuGet包还原失败"
        }
        
        # 构建发布
        Write-Log "编译发布应用..."
        dotnet publish -c Release -o publish --no-restore
        if ($LASTEXITCODE -ne 0) {
            throw "应用编译失败"
        }
        
        # 复制配置文件
        Copy-Item "appsettings.json" "publish/" -Force
        Copy-Item "appsettings.$Environment.json" "publish/" -Force -ErrorAction SilentlyContinue
        
        # 复制SSL证书
        if (Test-Path "ssl") {
            Copy-Item "ssl" "publish/" -Recurse -Force
        }
        
        Write-Log "服务端构建完成"
    } catch {
        Handle-Error "服务端构建失败" $_
    } finally {
        Pop-Location
    }
}

# 构建前端
function Build-H5 {
    if ($SkipBuild) {
        Write-Log "跳过前端构建"
        return
    }
    
    Write-Log "构建前端应用..."
    
    Push-Location $Config.H5Path
    try {
        # 安装依赖
        Write-Log "安装前端依赖..."
        npm install
        if ($LASTEXITCODE -ne 0) {
            throw "前端依赖安装失败"
        }
        
        # 构建生产版本
        Write-Log "构建生产版本..."
        npm run build
        if ($LASTEXITCODE -ne 0) {
            throw "前端构建失败"
        }
        
        Write-Log "前端构建完成"
    } catch {
        Handle-Error "前端构建失败" $_
    } finally {
        Pop-Location
    }
}

# 部署应用
function Deploy-Application {
    Write-Log "部署应用..."
    
    # 部署服务端
    if (Test-Path "$($Config.ServicePath)/publish") {
        Write-Log "部署服务端应用..."
        
        # 创建部署目录
        $deployDir = "C:\inetpub\$($Config.ServiceName)"
        if (!(Test-Path $deployDir)) {
            New-Item -ItemType Directory -Path $deployDir -Force | Out-Null
        }
        
        # 复制文件
        Copy-Item "$($Config.ServicePath)/publish/*" $deployDir -Recurse -Force
        
        Write-Log "服务端部署完成: $deployDir"
    }
    
    # 部署前端
    if (Test-Path "$($Config.H5Path)/dist") {
        Write-Log "部署前端应用..."
        
        # 创建前端部署目录
        $h5DeployDir = "C:\inetpub\wwwroot\refundtask"
        if (!(Test-Path $h5DeployDir)) {
            New-Item -ItemType Directory -Path $h5DeployDir -Force | Out-Null
        }
        
        # 复制文件
        Copy-Item "$($Config.H5Path)/dist/*" $h5DeployDir -Recurse -Force
        
        Write-Log "前端部署完成: $h5DeployDir"
    }
}

# 启动服务
function Start-Services {
    Write-Log "启动服务..."
    
    # 启动Windows服务
    $service = Get-Service -Name $Config.ServiceName -ErrorAction SilentlyContinue
    if ($service) {
        Start-Service -Name $Config.ServiceName
        Write-Log "Windows服务已启动"
    } else {
        # 直接启动可执行文件
        $exePath = "C:\inetpub\$($Config.ServiceName)\$($Config.ServiceName).exe"
        if (Test-Path $exePath) {
            Start-Process -FilePath $exePath -WorkingDirectory (Split-Path $exePath)
            Write-Log "应用进程已启动"
        } else {
            Handle-Error "找不到可执行文件: $exePath"
        }
    }
    
    # 等待服务启动
    Write-Log "等待服务启动..."
    Start-Sleep -Seconds 10
}

# 健康检查
function Test-Health {
    if ($SkipTest) {
        Write-Log "跳过健康检查"
        return
    }
    
    Write-Log "执行健康检查..."
    
    $healthUrl = "https://$($Config.Domain):$($Config.ApiPort)/health"
    $maxRetries = 10
    $retryCount = 0
    
    while ($retryCount -lt $maxRetries) {
        try {
            $response = Invoke-WebRequest -Uri $healthUrl -UseBasicParsing -TimeoutSec 10
            if ($response.StatusCode -eq 200) {
                Write-Log "健康检查通过: $healthUrl"
                break
            }
        } catch {
            $retryCount++
            if ($retryCount -ge $maxRetries) {
                Handle-Error "健康检查失败: $healthUrl" $_
            }
            Write-Log "健康检查重试 $retryCount/$maxRetries..."
            Start-Sleep -Seconds 5
        }
    }
    
    # 测试前端页面
    $h5Url = "https://$($Config.Domain):$($Config.H5Port)/refundtask/login"
    try {
        $response = Invoke-WebRequest -Uri $h5Url -UseBasicParsing -TimeoutSec 10
        if ($response.StatusCode -eq 200) {
            Write-Log "前端页面访问正常: $h5Url"
        }
    } catch {
        Write-Log "前端页面访问失败: $h5Url" "WARN"
    }
    
    # 测试企业微信接口
    $wechatTestUrl = "https://$($Config.Domain):$($Config.ApiPort)/api/senparc-wechat/auth-url"
    try {
        $testData = @{
            redirectUri = "https://$($Config.Domain):$($Config.ApiPort)/api/senparc-wechat/callback"
            state = "health_check"
        } | ConvertTo-Json
        
        $response = Invoke-WebRequest -Uri $wechatTestUrl -Method POST -Body $testData -ContentType "application/json" -UseBasicParsing -TimeoutSec 10
        if ($response.StatusCode -eq 200) {
            Write-Log "企业微信接口测试通过"
        }
    } catch {
        Write-Log "企业微信接口测试失败" "WARN"
    }
}

# 回滚部署
function Invoke-Rollback {
    param([string]$BackupPath)
    
    Write-Log "执行部署回滚..."
    
    if (!(Test-Path $BackupPath)) {
        Handle-Error "备份路径不存在: $BackupPath"
    }
    
    # 停止服务
    Stop-Services
    
    # 恢复服务端
    if (Test-Path "$BackupPath/service") {
        $deployDir = "C:\inetpub\$($Config.ServiceName)"
        Remove-Item "$deployDir/*" -Recurse -Force -ErrorAction SilentlyContinue
        Copy-Item "$BackupPath/service/*" $deployDir -Recurse -Force
        Write-Log "服务端回滚完成"
    }
    
    # 恢复前端
    if (Test-Path "$BackupPath/h5") {
        $h5DeployDir = "C:\inetpub\wwwroot\refundtask"
        Remove-Item "$h5DeployDir/*" -Recurse -Force -ErrorAction SilentlyContinue
        Copy-Item "$BackupPath/h5/*" $h5DeployDir -Recurse -Force
        Write-Log "前端回滚完成"
    }
    
    # 启动服务
    Start-Services
    
    Write-Log "回滚完成"
}

# 主函数
function Main {
    Write-Log "开始 $Action 操作 (环境: $Environment)"
    
    try {
        switch ($Action.ToLower()) {
            "deploy" {
                Test-Prerequisites
                Test-WeChatConfig
                $backupPath = New-Backup
                
                try {
                    Stop-Services
                    Build-Service
                    Build-H5
                    Deploy-Application
                    Start-Services
                    Test-Health
                    
                    Write-Log "部署成功完成!" "SUCCESS"
                    Write-Log "服务端地址: https://$($Config.Domain):$($Config.ApiPort)"
                    Write-Log "前端地址: https://$($Config.Domain):$($Config.H5Port)/refundtask/login"
                    Write-Log "健康检查: https://$($Config.Domain):$($Config.ApiPort)/health"
                } catch {
                    Write-Log "部署失败，执行回滚..." "ERROR"
                    Invoke-Rollback -BackupPath $backupPath
                    throw
                }
            }
            
            "test" {
                Test-Health
                Write-Log "测试完成"
            }
            
            "rollback" {
                # 查找最新的备份
                $latestBackup = Get-ChildItem "$($Config.BackupPath)/backup-*" | Sort-Object Name -Descending | Select-Object -First 1
                if ($latestBackup) {
                    Invoke-Rollback -BackupPath $latestBackup.FullName
                } else {
                    Handle-Error "未找到可用的备份"
                }
            }
            
            default {
                Handle-Error "未知操作: $Action。支持的操作: deploy, test, rollback"
            }
        }
    } catch {
        Handle-Error "操作失败" $_
    }
}

# 脚本入口
if ($MyInvocation.InvocationName -ne '.') {
    Main
}

<#
.SYNOPSIS
feoa.gfelz.com 企业微信登录快速部署脚本

.DESCRIPTION
这个脚本用于自动化部署企业微信登录功能到 feoa.gfelz.com 域名环境。
支持完整部署、健康检查和回滚操作。

.PARAMETER Action
操作类型: deploy(部署), test(测试), rollback(回滚)

.PARAMETER Environment
部署环境: production, staging, development

.PARAMETER SkipBuild
跳过构建步骤

.PARAMETER SkipTest
跳过测试步骤

.PARAMETER Force
强制部署，忽略端口占用等警告

.EXAMPLE
.\deploy-gfelz.ps1 -Action deploy
执行完整部署

.EXAMPLE
.\deploy-gfelz.ps1 -Action test
执行健康检查

.EXAMPLE
.\deploy-gfelz.ps1 -Action rollback
回滚到最新备份

.EXAMPLE
.\deploy-gfelz.ps1 -Action deploy -SkipBuild -Force
跳过构建，强制部署

.NOTES
使用前请确保:
1. 已安装.NET 9.0运行时
2. 已安装Node.js
3. SSL证书文件存在
4. 企业微信配置正确
5. 具有管理员权限
#>